/**
 * 
 */
package controller.xml;

import model.NoSuchDirectoryException;
import model.solver.ESolver;
import model.solver.ImportESolver;
import model.solver.SolverFactory;
import model.solver.SolverParameter;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

import controller.solver.Solver;

/**
 * Use to parse a {@link Solver} in the exported session in XML.
 * 
 * @author GRONOWSKI Stephane svan001@aol.com
 * 
 *         igsat 2010
 * 
 */
public class SolverXMLHandler extends XMLHandler {

	private Solver			solver			= null;
	private SolverXMLStatus	status			= SolverXMLStatus.NONE;
	private boolean			alreadyParam	= false;
	private SolverFactory	factory;

	/**
	 * Create a handler for xml parsing.
	 * 
	 * @param factory
	 *            a {@link SolverFactory}
	 */
	public SolverXMLHandler(SolverFactory factory) {
		this.factory = factory;
	}


	@Override
	public boolean characters2(char[] ch, int start, int length) throws SAXException {

		switch (status) {
		case NONE:
		case PARAMETER:
			throw new SAXException("not supposed to receive character in this status");
		default:
			return super.characters2(ch, start, length);
		}
	}

	@Override
	public boolean endDocument2() throws SAXException {
		return false;
	}

	@Override
	public boolean endElement2(String uri, String localName, String qName) throws SAXException {
		switch (status) {
		case NONE:
			return false;

		case PARAMETER:
			if (qName.equals(XMLBaliseFormat.PARAMETER))
			{// ferme parameter
				status = SolverXMLStatus.NONE;
				SolverParameter param = null;
				switch (solver.getType()) {
				case RSAT:
					param = ((RsatParameterXMLHandler) delegate).getParam();
					break;
				case MINISAT:
					param = ((MiniSatParameterXMLHandler) delegate).getParam();
					break;
				default:
					param = ((ImportedSolverParemeterXMLHandler) delegate).getParam();
				}
				if (param != null)
					solver.setSolverParameter(param);
				else
					throw new SAXException("problem parameter");

				delegate = null;
				return true;
			}
			throw new SAXException("end of PARAMETER was expected");

		case TYPE:
			if (qName.equals(XMLBaliseFormat.SOLVER_TYPE))
			{// ferme TYPE
				setType();
				status = SolverXMLStatus.NONE;
				return true;
			}
			throw new SAXException("end of TYPE was expected");
		}

		// attend une fin de balise qui existe pas...
		throw new SAXException("an other end of element was expected");
	}

	@Override
	public boolean startElement2(String arg0, String arg1, String arg2, Attributes arg3) throws SAXException {
		if (status != SolverXMLStatus.NONE)
			throw new SAXException("already have a started element");

		if (arg2.equals(XMLBaliseFormat.PARAMETER))
		{// balise parameter
			if (arg3.getLength() != 1)
				throw new SAXException("problem attribute for PARAMETER");
			String at = arg3.getValue(XMLBaliseFormat.TYPE_PARAMETER);
			if (!at.equals(XMLBaliseFormat.TYPE_PARAMETER_SOLVEUR))
				throw new SAXException("bad attribute for PARAMETER");

			if (alreadyParam)
				throw new SAXException("already have a PARAMETER");

			// set les donne pour recupere le parameter
			status = SolverXMLStatus.PARAMETER;
			switch (solver.getType()) {
			case MINISAT:
				delegate = new MiniSatParameterXMLHandler();
				break;
			case RSAT:
				delegate = new RsatParameterXMLHandler();
				break;
			default:
				delegate = new ImportedSolverParemeterXMLHandler();
				// throw new SAXException("problem solver type");
			}
			return true;
		}

		if (arg2.equals(XMLBaliseFormat.SOLVER_TYPE))
		{// balise type
			if (solver != null)
				throw new SAXException("already have a SOLVER");

			status = SolverXMLStatus.TYPE;
			return true;
		}
		// peut pas commencer balise qui existe pas
		throw new SAXException("unexpected balise: " + arg2);
	}

	/**
	 * Return the solver.
	 * 
	 * @return the solver
	 */
	public Solver getSolver() {
		return solver;
	}

	/**
	 * Set the type and create the {@link Solver}.
	 * 
	 * @throws SAXException
	 */
	private void setType() throws SAXException {
		ESolver type = ESolver.getValueFromXML(buffer.toString());
		ImportESolver importedType = factory.getAvailableImportByXML(buffer.toString());

		try
		{
			if (type != null)// solver normale
				solver = factory.createSolver(type);
			else
				if (importedType != null) // solver importer
					solver = factory.createImportSolver(importedType);

		} catch (NoSuchDirectoryException e)
		{
			e.printStackTrace();
			throw new SAXException("pb creating solver");
		}
		if (solver == null)
			throw new SAXException("unidentified solver");
	}

}
